package cn.mw.cmdb.processor;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.mw.cmdb.anno.CMDBHeader;
import cn.mw.cmdb.entity.InstanceGroupByPathAndStatus;
import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.entity.ModelInfo;
import cn.mw.cmdb.param.FunctionModuleEnum;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.ModelSearchParam;
import cn.mw.cmdb.param.TableSearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.CustomModelServiceImpl;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.util.AssetsTool;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.view.StaticsViewModel;
import cn.mw.cmdb.view.ViewConvertContext;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.microMonitorCommon.api.user.MwUserApi;
import cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem;
import cn.mw.microMonitorCommon.security.dto.MwUser;
import org.apache.commons.collections.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem.flexNum;

/**
 * 模型列表通用Processor
 */
public class StaticsProcessorFinanceModel implements TableDataProccessor {
    private CmdbServiceManage cmdbServiceManage;

    private TableSearchParam tableDataParam;

    public StaticsProcessorFinanceModel(CmdbServiceManage cmdbServiceManage, TableSearchParam tableDataParam) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.tableDataParam = tableDataParam;
    }

    @Override
    public List genData(TableDataProcessorContext context) throws Exception {
        CustomModelServiceImpl customModelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        // 查询所有金融元父模型的普通模型
        ModelSearchParam parentModelSearchParam=new ModelSearchParam();
        parentModelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<ModelInfo> financeParentModelInfos = customModelService.getAllModelByParentGroup(parentModelSearchParam);
        Map<String, ModelInfo> modelId2FinanceParentModelInfoMap = financeParentModelInfos.stream().collect(Collectors.toMap(ModelInfo::getId, item -> item, (o1, o2) -> o1));
        List<String> financeParentModelIds = financeParentModelInfos.stream().map(ModelInfo::getId).toList();
        List<Long> userIds = financeParentModelInfos.stream().map(ModelInfo::getCreater).collect(Collectors.toList());
        MwUserApi mwUserApi = (MwUserApi) context.get(ViewConvertContext.MwuserApiKey);
        List<MwUser> mwUsers = mwUserApi.getUsersByUserIds(userIds);
        Map<Long, String> userNampMap = new HashMap<>();
        if (null != mwUsers) {
            userNampMap = mwUsers.stream().collect(Collectors.toMap(MwUser::getId, MwUser::getUsername));
        }
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        //获取指定分组下的所有普通模型列表
        if (tableDataParam != null) {
            BeanUtil.copyProperties(tableDataParam, modelSearchParam, CopyOptions.create().setIgnoreNullValue(true));
        }
        // 查询所有金融元父模型普通模型
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getParentModelIds), new SubCondition(CriteriaOpsType.elemMatch.name(), financeParentModelIds));
        modelSearchParam.setGroupId(tableDataParam.getId());
        modelSearchParam.setPage(null);
        List<ModelInfo> modelInfos = customModelService.doSelectShowNormalModelByPath(modelSearchParam);

        List<StaticsViewModel> ret = new ArrayList<>();
        if (null != modelInfos && modelInfos.size() > 0) {
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            InstanceSearchParam param = new InstanceSearchParam();
            BeanUtil.copyProperties(context.getTableSearchParam(), param, CopyOptions.create().setIgnoreNullValue(true));
            param.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getFinanceParentId), new SubCondition(CriteriaOpsType.in.name(), financeParentModelIds));
            param.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
            List<InstanceGroupByPathAndStatus> groupRet = instanceService.groupCountByPathAndStatus(param);
            for (InstanceGroupByPathAndStatus instanceGroupByPathAndStatus:groupRet) {
                if (instanceGroupByPathAndStatus.getFinanceParentId()!=null&& CollectionUtils.isNotEmpty(instanceGroupByPathAndStatus.getPath())){
                    instanceGroupByPathAndStatus.getPath().remove(instanceGroupByPathAndStatus.getPath().size() - 1);
                    instanceGroupByPathAndStatus.getPath().add(String.format("%s_%s", instanceGroupByPathAndStatus.getGroupId(), instanceGroupByPathAndStatus.getFinanceParentId()));
                }
            }
            Map<String, List<AssetsTool.ItemAssetsStatusContext>> idContextMap = AssetsTool.initModelAndGroupIdSet(new HashSet<>(), new HashSet<>(), groupRet);

            StaticsViewModel modelStaticsView;
            ModelInfo parentModelInfo;
            Set<String> existsKey=new HashSet<>();
            String key;
            for (ModelInfo modelInfo : modelInfos) {
                // 普通模型替换成金融元父模型
                for (String parentModelId : modelInfo.getParentModelIds()) {
                    parentModelInfo=modelId2FinanceParentModelInfoMap.get(parentModelId);
                    if (parentModelInfo!=null) {
                        key = String.format("%s_%s", modelInfo.getGroupId(), parentModelId);
                        if (existsKey.contains(key)) {
                            continue;
                        }
                        existsKey.add(key);
                        parentModelInfo.setGroupId(modelInfo.getGroupId());
                        modelStaticsView = new StaticsViewModel();
                        modelStaticsView.extractFrom(parentModelInfo);
                        modelStaticsView.setId(key);
                        modelStaticsView.setCreater(userNampMap.get(parentModelInfo.getCreater()));

                        List<AssetsTool.ItemAssetsStatusContext> contexts = idContextMap.get(modelStaticsView.getId());
                        if (null != contexts) {
                            modelStaticsView.setInstanceNum((long) AssetsTool.calcItemAssetsStatusCount(contexts));
                        }else{
                            modelStaticsView.setInstanceNum(0L);
                        }
                        ret.add(modelStaticsView);
                    }
                }
            }
        }
        return ret;
    }

    @Override
    public List<TableHeaderItem> genDefaultTableHeader(Class clazz) throws Exception {
        BeanDesc desc = BeanUtil.getBeanDesc(clazz);
        Iterator<PropDesc> ite = desc.getProps().iterator();
        List<TableHeaderItem> tableHeaderItems = new ArrayList<>();
        while (ite.hasNext()) {
            PropDesc propDesc = ite.next();
            Field field = propDesc.getField();
            CMDBHeader annotation = field.getAnnotation(CMDBHeader.class);
            if (null != annotation) {
                TableHeaderItem item = new TableHeaderItem();
                item.setField(field.getName());
                item.setHeaderName(annotation.name());
                item.setVisible(annotation.visible());
                item.setFlex(flexNum);
                item.setParseType(annotation.relateDataProcesor());
                item.setPropertyTypeId(annotation.propertyTypeId());
                tableHeaderItems.add(item);
            }
        }
        return tableHeaderItems;
    }
}
